<template>
    <div ref="container" style="height: 100%;">
        <div style="padding: 1rem;display: flex;">
            <div @click="init"
                style="display: flex;justify-content: center;align-items: center;margin-right: 10px;cursor: pointer;">
                <el-icon>
                    <RefreshLeft />
                </el-icon></div>
            <ElButton @click="uploadFile">上传</ElButton>
            <ElButton @click="showAddfolderDialog = true">新建文件夹</ElButton>

            <el-badge
                :value="uploadFileList.filter(x => !x.abort).length == 0 ? '' : uploadFileList.filter(x => !x.abort).length">
                <ElButton @click="showUploadDialog = true">查看上传列表</ElButton>
            </el-badge>
        </div>
        <header>
            <!-- <button :disabled="pathList.length == 1" @click="gobackward">{{ '<' }}</button> -->
            <div style="display: flex;justify-content: center;align-items: center;margin-left: 10px;cursor: pointer;"
                @click="gobackward"><el-icon>
                    <ArrowLeft />
                </el-icon></div>
            <div @click="redirectFolder(key)" v-for="item, key in pathList" style="margin-left: 2px;padding: 3px; 
                    border-radius: 6px;cursor: pointer;">
                <el-tag round>
                    {{ item }}
                </el-tag>
            </div>
        </header>
        <main v-loading="loading" ref="main">
            <FileItem @start-drag="startDrag" @end-drag="endDrag" @dblclick="handleDblClick(item)"
                :filename="item.fileName" :isFolder="item.folderFlag" v-for="item in currentFileList" :f-item="item">
            </FileItem>
        </main>
        <CommomMenu @init="init" @uploadFile="uploadFile" :menu-coorderate="menuCoorderate"
            :show-common-menu="showCommonMenu"></CommomMenu>
        <TargetMenu :menu-coorderate="menuCoorderate" :show-target-menu="showTargetMenu" :is-trash-bin="isTrashBin"
            @handler-download="handlerDownload" @handler-open="handlerOpen" @rename="rename" @del="del" @resume="resume" ></TargetMenu>
        <NewFolderDialog @success="() => { showAddfolderDialog = false; init() }" @close="showAddfolderDialog = false"
            :show-addfolder-dialog="showAddfolderDialog" :current-folder="currentFolder" />
        <RenameDialog :current-folder="currentFolder" @close="showRenameDialog = false"
            @success="() => { showRenameDialog = false; init() }" :old-name="currentItem?.fileName"
            :show="showRenameDialog" />
        <UploadDialog :upload-file-list="uploadFileList" @close="() => showUploadDialog = false"
            :dialog-visible="showUploadDialog" />
    </div>
</template>
<script setup lang="ts">
import { ElButton, ElMessage } from 'element-plus';
import { computed, onMounted, reactive, ref } from 'vue'
import FileItem from './FileItem.vue';
import NewFolderDialog from './NewFolderDialog.vue';
import CommomMenu from './CommomMenu.vue';
import UploadDialog from './UploadDialog.vue';
import RenameDialog from './RenameDialog.vue';
import TargetMenu from './TargetMenu.vue';
import fileApi from '@/api/file'
import { TRASH_BIN_NAME } from '@/constant';

const showAddfolderDialog = ref(false)
const showRenameDialog = ref(false)
const showUploadDialog = ref(false)
const container = ref<HTMLDivElement>()
const main = ref<HTMLDivElement>()
const showCommonMenu = ref(false)
const showTargetMenu = ref(false)
const loading = ref(true)
const currentItem = ref<FItem>()
const pathList = ref<string[]>(['首页'])
const currentDraggingItem = ref<FItem>()
// const oldName = computed(() => {
//     return currentItem.value?.fileName
// })
// 获得当前文件夹，‘逗号分隔！’
const currentFolder = computed(() => {
    let r = ''
    for (let index = 1; index < pathList.value.length; index++) {
        const element = pathList.value[index];
        if (index === pathList.value.length - 1) {
            r += element
        } else {
            r += element + ','
        }
    }
    return r
})
const isTrashBin = computed(() => {
    ;

    return pathList.value[1] === TRASH_BIN_NAME
})
const currentFileList = ref<FItem[]>([])
const init = () => {
    loading.value = true
    currentFileList.value = []
    fileApi.getCurrentItems(currentFolder.value).then(res => {
        currentFileList.value = res.data.value
        loading.value = false
    })
}
init()
function handleDblClick(item: FItem) {
    if (item.folderFlag) {
        // goto folder
        gotoFolder(item.fileName)
    } else {
        tryOpenInBroswer(item)
    }
}
function handlerOpen() {

    if (currentItem.value?.folderFlag) {
        // goto folder
        gotoFolder(currentItem.value.fileName)
    } else {
        tryOpenInBroswer(currentItem.value as FItem)
    }
}
function handlerDownload() {
    if (currentItem.value?.folderFlag.valueOf()) {
        // not support!
        ElMessage({
            message: '不支持直接下载文件夹。。。😭',
            type: 'warning'
        })
    } else {
        // download 
        let path
        if (currentFolder.value == '') {
            path = currentItem.value?.fileName
        } else {
            path = currentFolder.value + '/' + currentItem.value?.fileName
        }
        console.log("/stuff/" + path);
        const a = document.createElement('a')
        a.href = "/api/stuff/" + path
        a.download = currentItem.value?.fileName as string
        a.click()
    }
}
function getRandomString(length: number) {
    let result = '';
    const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    const charactersLength = characters.length;
    for (let i = 0; i < length; i++) {
        result += characters.charAt(Math.floor(Math.random() * charactersLength));
    }
    return result;
}

function getInitFIle(item: File) {
    let sliceNumber = Math.floor(item.size / threshold)
    if (sliceNumber * threshold < item.size) {
        sliceNumber += 1
    }
    const f: UploadFile = {
        name: item.name,
        speed: '准备中',
        suspend: false,
        totalSlice: sliceNumber,
        uploadedSlice: 0,
        abort: false,
        lock: () => {
            return new Promise(r => {

                f.unlock = r
            })
        },
        unlock: () => { },
        progress: 0,
        abortController: new AbortController(),
    }
    return f
}
const B = 1;
const KB = B * 1024;
const MB = KB * 1024;
const threshold = 5 * MB
const GB = MB * 1024;
async function sliceUploadFile(item: File) {

    const f = getInitFIle(item)

    const len = uploadFileList.value.push(f)
    const sliceFileName = getRandomString(10)
    const c = currentFolder.value
    for (let index = 0; index < f.totalSlice; index++) {
        const start = index * threshold
        let end = (index + 1) * threshold
        if (end > item.size) {
            end = item.size
        }
        const startTime = new Date().getTime()
        const blob = item.slice(start, end)
        try {
            await fileApi.uploadSlice(blob, sliceFileName + index, uploadFileList.value[len - 1].abortController)
        } catch (e) {
            console.log("取消请求");

        }

        const endTime = new Date().getTime()


        if (!uploadFileList.value[len - 1].abort && uploadFileList.value[len - 1].suspend) {
            console.log('suspended!')
            await uploadFileList.value[len - 1].lock()
        }
        if (uploadFileList.value[len - 1].abort) {
            // TODO clean all have been uploaded .
            fileApi.abort(sliceFileName, uploadFileList.value[len - 1].uploadedSlice)
            break
        }

        const speed = ((blob.size / MB) / ((endTime - startTime) / 1000)).toFixed(2)
        uploadFileList.value[len - 1].speed = speed + 'MB/s'
        uploadFileList.value[len - 1].uploadedSlice = index + 1
        uploadFileList.value[len - 1].progress = Math.floor((uploadFileList.value[len - 1].uploadedSlice / uploadFileList.value[len - 1].totalSlice) * 100)

    }
    if (uploadFileList.value[len - 1].abort) {
        // uploadFileList.value.splice(len - 1, 1) 不在这里做 因为其他的删除会影响到这个len 。。。。
    } else {
        fileApi.coalesce(c, sliceFileName, item.name, f.totalSlice)
    }

}


const uploadFileList = ref<UploadFile[]>([])
const fileChange = (e: Event) => {
    const ipt = e.target as HTMLInputElement
    doUploadFile(ipt.files as FileList)
}

async function straightUploadFile(item: File) {

    const f = getInitFIle(item)

    const len = uploadFileList.value.push(f)

    fileApi.upload(item, currentFolder.value, (e) => {
        uploadFileList.value[len - 1].progress = Math.floor(e.loaded / (e.total as number) * 100)
        uploadFileList.value[len - 1].speed = "MAX!"
    }, uploadFileList.value[len - 1].abortController).then(res => {
        console.log(res.data.message);
        uploadFileList.value[len - 1].uploadedSlice = uploadFileList.value[len - 1].totalSlice
        init()
    }).catch(e => {
        ElMessage({ type: 'success', message: '取消成功🏅' })
    })
}

function doUploadFile(files: FileList) {
    for (const item of files) {
        if (item.type === "") continue
        if (item.size > threshold) {
            sliceUploadFile(item).then(r => {
                init()
            })
        } else {
            straightUploadFile(item)
        }
    }
}

function uploadFile() {
    const input = document.createElement('input') as HTMLInputElement
    input.type = 'file'
    input.multiple = true
    input.onchange = fileChange
    input.click()
}

function gotoFolder(folderName: string) {
    pathList.value.push(folderName)
    init()
}
function redirectFolder(index: number) {
    pathList.value = pathList.value.slice(0, index + 1)
    init()
}

const menuCoorderate = reactive({
    left: '',
    top: ''
})
function gobackward() {
    if (pathList.value.length === 1) {
        return
    }
    const v = pathList.value.pop()
    init()
}
function goforward() {

}
function del() {
    if(currentItem.value?.folderFlag && currentItem.value.fileName == TRASH_BIN_NAME) {
        ElMessage({type:'warning',message:'不能删除回收站😭！'})
        return
    }
    if (isTrashBin.value) {
        console.log('do real del');
    } else {
        console.log('move to trash');
        fileApi.del(currentItem.value!.fileName, currentFolder.value).then(res => {
            init()
        })
    }
}
function resume () {
     fileApi.resume(currentItem.value!.fileName, currentFolder.value).then(res => {
         init()
     })
}
function startDrag(item: FItem) {
    currentDraggingItem.value = item
}
function endDrag(item: FItem) {
    if (!currentDraggingItem.value) {
        return
    }
    console.log(currentDraggingItem.value.fileName + '-> ' + item.fileName);
    fileApi.mv(currentDraggingItem.value.fileName, item.fileName, currentFolder.value).then(res => {
        init()
    })
    currentDraggingItem.value = undefined

}

function rename() {
    showRenameDialog.value = true
}
onMounted(() => {
    const contextmenuHandler = (e: any) => {
        e.preventDefault()
        let target = e.target as HTMLDivElement | any
        // console.log(target == main.value);
        showCommonMenu.value = false
        showTargetMenu.value = false
        menuCoorderate.left = e.clientX + 'px'
        menuCoorderate.top = e.clientY + 'px'
        if (container.value!.clientWidth - e.clientX < 100) {
            menuCoorderate.left = e.clientX - 100 + 'px'
        }
        if (container.value!.clientHeight - e.clientY < 200) {
            menuCoorderate.top = e.clientY - 200 + 'px'
        }
        console.log(target == main.value);

        if (target == main.value || target == container.value) {
            showCommonMenu.value = true
        } else {
            showTargetMenu.value = true
            while (true) {
                if (target.attributes.filename) {
                    console.log(target.attributes.filename.value);
                    currentItem.value = {
                        fileName: target.attributes.filename.value,
                        createTime: '',
                        folderFlag: target.attributes.isFolder.value === "true" ? true : false
                    }
                    break
                } else {
                    target = target.parentElement as HTMLDivElement
                }
            }
        }

        const x = (e: any) => {
            showCommonMenu.value = false
            showTargetMenu.value = false
            window.removeEventListener('click', x)
        }
        window.addEventListener('click', x)
    }
    let timmer: any = null

    container.value?.addEventListener('touchstart', (e) => {
        timmer = setTimeout(() => {
            contextmenuHandler(e)
        }, 500);
    })
    container.value?.addEventListener('touchend', (e) => {
        clearTimeout(timmer)
    })
    container.value?.addEventListener('contextmenu', contextmenuHandler)
    container.value?.addEventListener('drop', (e) => {
        e.preventDefault()

        console.log();
        const f = e.dataTransfer?.files as FileList
        doUploadFile(f)
    })
    container.value?.addEventListener('dragover', (e) => {
        e.preventDefault()
    })
})

function tryOpenInBroswer(item: FItem) {
    throw new Error('Function not implemented.');
}
</script>
<style scoped>
header {
    display: flex;
    flex-direction: row;
}

main {
    padding: 2rem;
    display: flex;
    flex-wrap: wrap;
    flex: 1;
}
</style>